package com.xhq.digitaltwin.config.mqtt;

import com.xhq.digitaltwin.service.CoreBusinessService;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 回调类
 */
@Component
public class MyMQTTCallback implements MqttCallbackExtended {
    /**
     * 手动注入
     */
    //private final MqttConfiguration mqttConfiguration = SpringUtils.getBean(MqttConfiguration.class);

    private static final Logger log = LoggerFactory.getLogger(MyMQTTCallback.class);

    /**
     * 保存数据
     */
    @Autowired
    private CoreBusinessService coreBusinessService;

    /**
     * 丢失连接，可在这里做重连
     * 只会调用一次
     *
     * @param throwable
     */
    @Override
    public void connectionLost(Throwable throwable) {
        log.error("mqtt connectionLost 连接断开，3S之后尝试重连: {}", throwable.getMessage());
        long reconnectTimes = 1;
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e1) {
        }
        while (true) {
            try {
                try {
                    //这里好像没法跳出循环。
                    if (MyMQTTClient.getClient().isConnected()) {
                        //判断已经重新连接成功  需要重新订阅主题 可以在这个if里面订阅主题  或者 connectComplete（方法里面）  看你们自己选择

                        coreBusinessService.subscribeAllReconnection(MyMQTTClient.getClient());

                        log.warn("mqtt reconnect success end  重新连接  重新订阅成功");
                        return;
                    }
                } catch (Exception e) {
                    log.info("首次断开连接，未重连，尝试 获取连接异常");
                }

                log.warn("mqtt reconnect times = {} try again...  mqtt重新连接时间 {}", reconnectTimes, reconnectTimes);
                MyMQTTClient.getClient().reconnect();

                //.getClient().reconnect()方法执行后，这个 .isConnected() 立刻执行，是返回false的，如果在循环一遍 很可能返回true，但是也可能返回false。所以代码这些写。
                if (MyMQTTClient.getClient().isConnected()) {
                    //判断已经重新连接成功  需要重新订阅主题 可以在这个if里面订阅主题  或者 connectComplete（方法里面）  看你们自己选择

                    coreBusinessService.subscribeAllReconnection(MyMQTTClient.getClient());

                    log.warn("mqtt reconnect success end  重新连接  重新订阅成功");
                    return;
                }
                reconnectTimes += 1;

            } catch (MqttException e) {
                log.error("mqtt断连异常", e);
                //特殊处理
                if ("已连接客户机".equals(e.getMessage())) {

                    coreBusinessService.subscribeAllReconnection(MyMQTTClient.getClient());

                    log.warn("mqtt reconnect success end  重新连接  重新订阅成功");
                    return;
                }
            }
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e1) {
            }
        }
    }

    /**
     * @param topic
     * @param mqttMessage
     * @throws Exception subscribe后得到的消息会执行到这里面
     *                   订阅者收到消息之后执行
     *                   throws Exception
     */
    @Override //注意了，这里如果执行超市，就会触发 连接丢失的逻辑。connectionLost(Throwable throwable)
    public void messageArrived(String topic, MqttMessage mqttMessage) {
        try {
            log.info("接收消息主题 : {}", topic);

            coreBusinessService.save(topic, mqttMessage);

            //System.out.println("服务端发完消息之后调用");
            //log.info("接收消息主题 : {}，接收消息内容 : {}", topic, new String(mqttMessage.getPayload()));
        } catch (Exception e) {
            e.printStackTrace();
            log.info("接收消息主题 : {}，接收消息内容 : {}，处理业务出错了", topic, new String(mqttMessage.getPayload()));
        }
    }


    /**
     * 连接成功后的回调 可以在这个方法执行 订阅主题  生成Bean的 MqttConfiguration方法中订阅主题 出现bug
     * 重新连接后  主题也需要再次订阅  将重新订阅主题放在连接成功后的回调 比较合理
     *
     * @param reconnect
     * @param serverURI
     */
    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        log.info("MQTT 连接成功，连接方式：{}", reconnect ? "重连" : "直连");
        //订阅主题(可以在这里订阅主题)

        //这里订阅主题怕是 不太行，如果注入 client端，那就有循环依赖的问题了
    }

    /**
     * * 消息到达后
     * subscribe后，执行的回调函数
     * publish后，配送完成后回调的方法
     *
     * @param iMqttDeliveryToken
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        //System.out.println("接收到已经发布的 QoS 1 或 QoS 2 消息的传递令牌时调用");
        //log.info("==========deliveryComplete={}==========", iMqttDeliveryToken.isComplete());
    }

}


